
#include <BMesh>
#include "member_BCone.h"

using namespace BWE;

member_BCone::member_BCone(BCone* cone)
{
	boss = cone;
	radius = 0.5;
	height = 1.0;
	sides = 12;
	segments = 1;
	radiusSegments = 1;
	//m_dimension[0] = m_radius;
	//m_dimension[1] = m_radius;
	//m_dimension[2] = m_height;
	prepare();
}
member_BCone::~member_BCone()
{

}

void member_BCone::prepare()
{
	if (sines.size() != sides)
	{
		sines.resize(sides);
		coses.resize(sides);
		for (int i = 0; i < sides; i++)
		{
			BReal angle = i * PI / sides * 2;
			coses[i] = cos(angle);
			sines[i] = sin(angle);
		}
	}
}
void member_BCone::rebuild()
{
	if (segments < 1)
		return;

	int flankNumVerts = sides * segments + 1;
	int bottomNumVerts = sides * radiusSegments + 1;
	int totalNumVerts = flankNumVerts + bottomNumVerts;

	BVectorArray* vertices = boss->vertices();
	BVectorArray* normals = boss->normals();
	BCoordArray* texCoords = boss->texCoords();

	if (!vertices || vertices->size() != totalNumVerts)
	{
		vertices = new BVectorArray(totalNumVerts);
		normals = new BVectorArray(totalNumVerts);
		texCoords = new BCoordArray(totalNumVerts);
		boss->setVertices(vertices);
		boss->setNormals(normals);
		boss->setTexCoords(texCoords);
	}

	boss->clearElements();

	{// make flank vertices.
		float sth = 1.0f / sides;
		float stv = 1.0f / segments;
		BReal sr = radius / segments;
		BReal sh = height / segments;
		for (int r = 0; r < segments; r++)
		{
			BReal rr = radius - sr * r;
			BReal z = sh * r;
			float ty = stv * (float)rr;
			int head = r * sides;
			for (int c = 0; c < sides; c++)
			{
				BReal x = coses[c] * rr;
				BReal y = sines[c] * rr;
				float tx = sth * c;
				vertices->set(head + c, BVector(x, y, z));
				texCoords->set(head + c, BCoord(tx, ty));
				BVector normal(x, y, z);
				normal.normalize();
				normals->set(head + c, normal);
			}
		}
		(*vertices)[flankNumVerts - 1] = BVector(0, 0, height);
		(*normals)[flankNumVerts - 1] = BVector(0, 0, 1);
		(*texCoords)[flankNumVerts - 1] = BCoord(0.5f, 0.0f);
	}

	{//make flank quads and top triangles.
		BIntArray* flankIndices = new BIntArray(sides * (segments - 1) * 4);
		for (int r = 0; r < segments - 1; r++)
		{
			int head = sides * r;
			int pos = sides * r * 4;
			for (int c = 0; c < sides; c++)
			{
				int index0 = head + c;
				int index1 = head + (c + 1) % sides;
				int index2 = index0 + sides;
				int index3 = index1 + sides;
				(*flankIndices)[pos + c * 4] = index0;
				(*flankIndices)[pos + c * 4 + 1] = index1;
				(*flankIndices)[pos + c * 4 + 2] = index3;
				(*flankIndices)[pos + c * 4 + 3] = index2;
			}
		}
		boss->addElement(Primitive_Quads, flankIndices)->setName("flank");

		BIntArray* topIndices = new BIntArray(sides * 3);
		int head = flankNumVerts - 1 - sides;
		int top = flankNumVerts - 1;
		for (int i = 0; i < sides; i++)
		{
			int index0 = head + i;
			int index1 = head + (i + 1) % sides;
			(*topIndices)[i * 3] = index0;
			(*topIndices)[i * 3 + 1] = index1;
			(*topIndices)[i * 3 + 2] = top;
		}
		boss->addElement(Primitive_Triangles, topIndices)->setName("flank-top");
	}

	{// make bottom vertices.
		BVector bottomNormal(0, 0, -1);
		BReal dr = radius / radiusSegments;
		for (int j = 0; j < radiusSegments; j++)
		{
			BReal r = radius - dr * j;
			int head = flankNumVerts + j * sides;
			for (int i = 0; i < sides; i++)
			{
				BReal x = coses[i] * r;
				BReal y = sines[i] * r;
				vertices->set(head + i, BVector(x, y, 0));
				normals->set(head + i, bottomNormal);
			}
		}
		(*vertices)[totalNumVerts - 1] = BVector(0, 0, 0);
		(*normals)[totalNumVerts - 1] = bottomNormal;
	}

	BReal down = height * BReal(0.25);
	for (int i = 0; i < vertices->size(); i++)
	{
		vertices->at(i).z() -= down;
	}
	if (bottomNumVerts < 1)
	{
		BIntArray* bottomIndices = new BIntArray(sides);
		int first = flankNumVerts;
		for (int i = 0; i < sides; i++)
		{
			(*bottomIndices)[i] = first + i;
		}
		boss->addElement(Primitive_Polygon, bottomIndices)->setName("bottom");
	}
	else
	{
		BIntArray* bottomIndices = new BIntArray(sides * (radiusSegments - 1) * 4);
		for (int r = 0; r < radiusSegments - 1; r++)
		{
			int head = flankNumVerts + sides * r;
			int pos = r * sides * 4;
			for (int c = 0; c < sides; c++)
			{
				int index0 = head + c;
				int index1 = head + (c + 1) % sides;
				int index2 = index0 + sides;
				int index3 = index1 + sides;
				(*bottomIndices)[pos + c * 4] = index0;
				(*bottomIndices)[pos + c * 4 + 1] = index2;
				(*bottomIndices)[pos + c * 4 + 2] = index3;
				(*bottomIndices)[pos + c * 4 + 3] = index1;
			}
		}
		boss->addElement(Primitive_Quads, bottomIndices)->setName("bottom");

		BIntArray* bottomCentralIndices = new BIntArray(sides * 3);
		int head = totalNumVerts - sides - 1;
		int center = totalNumVerts - 1;
		for (int i = 0; i < sides; i++)
		{
			int index0 = head + i;
			int index1 = head + (i + 1) % sides;
			(*bottomCentralIndices)[i * 3] = index0;
			(*bottomCentralIndices)[i * 3 + 1] = center;
			(*bottomCentralIndices)[i * 3 + 2] = index1;
		}
		boss->addElement(Primitive_Triangles, bottomCentralIndices)->setName("bottom-center");
	}
}
